/**  
* Copyright (c) 2008, Noel Lynch All rights reserved. Redistribution and use  
* in source and binary forms, with or without modification, are permitted  
* provided that the following conditions are met: Redistributions of source  
* code must retain the above copyright notice, this list of conditions and the  
* following disclaimer. Redistributions in binary form must reproduce the above  
* copyright notice, this list of conditions and the following disclaimer in the  
* documentation and/or other materials provided with the distribution. Neither  
* the name of Noel Lynch nor the names of contributors may be used to  
* endorse or promote products derived from this software without specific prior  
* written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*/
// Jul 29, 2008

package com.sceneworker.monitorpopup;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import java.util.concurrent.Callable;

import javax.swing.JDialog;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.tree.TreePath;

import com.jme.bounding.BoundingSphere;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.BillboardNode;
import com.jme.scene.DistanceSwitchModel;
import com.jme.scene.Node;
import com.jme.scene.PassNode;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial;
import com.jme.scene.Text;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.lod.AreaClodMesh;
import com.jme.scene.lod.DiscreteLodNode;
import com.jme.scene.shape.Arrow;
import com.jme.scene.shape.AxisRods;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Capsule;
import com.jme.scene.shape.Cylinder;
import com.jme.scene.shape.Disk;
import com.jme.scene.shape.Dome;
import com.jme.scene.shape.PQTorus;
import com.jme.scene.shape.Pyramid;
import com.jme.scene.shape.Quad;
import com.jme.scene.shape.RoundedBox;
import com.jme.scene.shape.Sphere;
import com.jme.scene.shape.Teapot;
import com.jme.scene.shape.Torus;
import com.jme.scene.shape.Tube;
import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueueManager;
import com.jme2utils.staticutils.ModelUtils;
import com.jme2utils.staticutils.ModelUtils.IImportFile;
import com.sceneworker.app.globals.SceneWorkerDialogManager;
import com.sceneworker.app.globals.SceneWorkerGlobals;
import com.sceneworker.editors.terraincreator.TerrainCreator;
import com.sceneworker.monitorpopup.panels.CreateLensFlarePanel;
import com.sceneworker.monitorpopup.panels.ImportDialogPanel;
import com.sceneworker.monitorpopup.panels.ReorganiseChildrenPanel;


public class NodeMenu extends BaseMenu implements ActionListener {
	
	private static final String IMPORT_X3D = "Import X3D";
	private static final String IMPORT_MS3D = "Import MS3D";
	private static final String IMPORT_ASE = "Import ASE";
	private static final String IMPORT_MD5 = "Import MD5";
	private static final String IMPORT_MD2 = "Import MD2";
	private static final String IMPORT_3DS = "Import 3DS";
	private static final String IMPORT_COLLADA_DAE = "Import Collada DAE";
	private static final String IMPORT_OGRE_XML = "Import Ogre XML";
	private static final String IMPORT_OBJ = "Import OBJ";
	private static final String IMPORT_JME = "Import JME";
	private static final String ADD_LENS_FLARE = "Add Lens Flare";
	private static final String REORGANISE_CHILDREN = "Reorganise Children";
	private static final String NEW_TERRAIN = "Add Terrain";
	private static final String ADD_AXIS_RODS = "Add Axis Rods";
	private static final String ADD_TUBE = "Add Tube";
	private static final String ADD_TORUS = "Add Torus";
	private static final String ADD_ROUNDED_BOX = "Add Rounded Box";
	private static final String ADD_PYRAMID = "Add Pyramid";
	private static final String ADD_PQTORUS = "Add PQTorus";
	private static final String ADD_DOME = "Add Dome";
	private static final String ADD_TEAPOT = "Add Teapot";
	private static final String ADD_DISK = "Add Disk";
	private static final String DISCRETE_LOD_NODE = "Add DiscreteLOD Node";
	private static final String ADD_SKY_BOX = "Add SkyBox";
	private static final String NEW_PASS_NODE = "Add New Pass Node";
	private static final String ADD_SPHERE = "Add Sphere";
	private static final String ADD_CAPSULE = "Add Capsule";
	private static final String ADD_CYLINDER = "Add Cylinder";
	private static final String ADD_ARROW = "Add Arrow";
	private static final String ADD_BILLBAORD = "Add Billbaord";
	private static final String ADD_QUAD = "Add Quad";
	private static final String NEW_NODE = "New Node";
	private static final String ADD_TEXT = "Add Text";
	private static final String ADD_BOX = "Add Box";
	private static final String IMPORT_CHILD = "Import Child";
	private static final String IMPORT_FOLDER = "Import Folder";
	private static final String ADD_FULL_SCREEN_QUAD = "Add Full Screen Quad";
	
	
	private		Node		mcl_node;
	
	static	private		Hashtable<String, CreateNewSpatial>	mcla_createObjectsCommands = null;
	
	static	private		void	registerDefaultSpatialCreators() {
		mcla_createObjectsCommands.put(NEW_PASS_NODE, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new PassNode("PassNode" + cl_parentNode.getQuantity());
			}
		});
		
		mcla_createObjectsCommands.put(ADD_BOX, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Box("Box" + cl_parentNode.getQuantity(), new Vector3f(), 5f, 5f, 5f);
			}
		});
		
		mcla_createObjectsCommands.put(ADD_SKY_BOX, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				Skybox		lcl_skyBox = new Skybox("SkyBox" + cl_parentNode.getQuantity(), 10, 10, 10);
				return lcl_skyBox;
			}
		});
		
		mcla_createObjectsCommands.put(ADD_TEXT, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return Text.createDefaultTextLabel("NewText");
			}
		});
		
		mcla_createObjectsCommands.put(NEW_NODE, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Node("Node" + cl_parentNode.getQuantity());
			}
		});
		
		mcla_createObjectsCommands.put(ADD_CYLINDER, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Cylinder("Cylinder" + cl_parentNode.getQuantity(), 10, 10, 5, 10);
			}
		});
		
		mcla_createObjectsCommands.put(ADD_SPHERE, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Sphere("Sphere" + cl_parentNode.getQuantity(), 10, 10, 10);
			}
		});
		
		mcla_createObjectsCommands.put(ADD_CAPSULE, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Capsule("Capsule" + cl_parentNode.getQuantity(), 10, 10, 10, 5, 10);
			}
		});
		
		mcla_createObjectsCommands.put(ADD_QUAD, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Quad("Quad" + cl_parentNode.getQuantity(), 5, 5);
			}
		});
		
		mcla_createObjectsCommands.put(ADD_BILLBAORD, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new BillboardNode("Billboard" + cl_parentNode.getQuantity());
			}
		});
		
		mcla_createObjectsCommands.put(ADD_ARROW, new CreateNewSpatial() {
			public Spatial createSpatial(Node cl_parentNode) {
				return new Arrow("Arrow" + cl_parentNode.getQuantity(), 5, 1);
			}
		});
		
		mcla_createObjectsCommands.put(DISCRETE_LOD_NODE, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new DiscreteLodNode("LOD" + cl_parentNode.getQuantity(), new DistanceSwitchModel());
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_DISK, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new Disk("Disk" + cl_parentNode.getQuantity(), 10, 10, 5);
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_TEAPOT, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new Teapot("Teapot" + cl_parentNode.getQuantity());
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_DOME, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new Dome("Dome" + cl_parentNode.getQuantity(), 10, 10, 10);
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_PQTORUS, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new PQTorus("PQTorus " + cl_parentNode.getQuantity(), 1, 0, 2, 1, 128, 16);
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_PYRAMID, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new Pyramid("Pyramid " + cl_parentNode.getQuantity(), 10, 10);
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_ROUNDED_BOX, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new RoundedBox("RoundedBox " + cl_parentNode.getQuantity(), new Vector3f(5, 5, 5));
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_TORUS, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new Torus("Torus " + cl_parentNode.getQuantity(), 10, 10, 1, 10);
			}
			
		});
		
		mcla_createObjectsCommands.put(ADD_TUBE, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new Tube("Tube " + cl_parentNode.getQuantity(), 10f, 10f, 10f);
			}
		});
		
		mcla_createObjectsCommands.put(ADD_AXIS_RODS, new CreateNewSpatial() {

			public Spatial createSpatial(Node cl_parentNode) {
				return new AxisRods("Axis Rods " + cl_parentNode.getQuantity(), true, 5, 0.2f);
			}
		});		
		
	}
	
	public
	NodeMenu(TreePath cl_selectedPath, SceneWorkerPopUp cl_menu) {
		super(cl_menu);
		
		mcl_node = (Node)cl_selectedPath.getLastPathComponent();
		
		if(mcla_createObjectsCommands == null) {
			mcla_createObjectsCommands = new Hashtable<String, CreateNewSpatial>();
			registerDefaultSpatialCreators();
		}
		
		buildMenu();
	}
	
	@Override
	protected	void
	buildMenu() {
		mcl_menu.add(buildAMenuItem(NEW_NODE));
		
		JMenu			lcl_importMenu = new JMenu("Import...");
		lcl_importMenu.add(buildAMenuItem(IMPORT_JME));
		lcl_importMenu.add(buildAMenuItem(IMPORT_OBJ));
		lcl_importMenu.add(buildAMenuItem(IMPORT_OGRE_XML));
		lcl_importMenu.add(buildAMenuItem(IMPORT_COLLADA_DAE));
		lcl_importMenu.add(buildAMenuItem(IMPORT_3DS));
		lcl_importMenu.add(buildAMenuItem(IMPORT_MD2));
		lcl_importMenu.add(buildAMenuItem(IMPORT_MD5));
		lcl_importMenu.add(buildAMenuItem(IMPORT_ASE));
		lcl_importMenu.add(buildAMenuItem(IMPORT_MS3D));
		lcl_importMenu.add(buildAMenuItem(IMPORT_X3D));
		
		mcl_menu.add(lcl_importMenu);
		
		//mcl_menu.add(buildAMenuItem(IMPORT_CHILD));
		mcl_menu.add(buildAMenuItem(IMPORT_FOLDER));
		mcl_menu.add(buildAMenuItem(REORGANISE_CHILDREN));
		
		mcl_menu.addSeparator();
		
		JMenu			lcl_newMenu = new JMenu("New Node Type...");
		lcl_newMenu.add(buildAMenuItem(NEW_TERRAIN));
		lcl_newMenu.add(buildAMenuItem(NEW_PASS_NODE));
		lcl_newMenu.add(buildAMenuItem(ADD_SKY_BOX));
		lcl_newMenu.add(buildAMenuItem(ADD_LENS_FLARE));
		lcl_newMenu.add(buildAMenuItem(DISCRETE_LOD_NODE));
		lcl_newMenu.add(buildAMenuItem(ADD_BILLBAORD));
		lcl_newMenu.add(buildAMenuItem(ADD_ARROW));
		lcl_newMenu.add(buildAMenuItem(ADD_AXIS_RODS));
		lcl_newMenu.add(buildAMenuItem(ADD_FULL_SCREEN_QUAD));
		
		mcl_menu.add(lcl_newMenu);
		
		JMenu			lcl_primitiviesMenu = new JMenu("New Primitive...");
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_QUAD));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_SPHERE));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_BOX));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_TEXT));
		
		lcl_primitiviesMenu.addSeparator();
		
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_CYLINDER));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_CAPSULE));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_DISK));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_DOME));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_PYRAMID));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_TORUS));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_TUBE));
		
		lcl_primitiviesMenu.addSeparator();
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_ROUNDED_BOX));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_PQTORUS));
		lcl_primitiviesMenu.add(buildAMenuItem(ADD_TEAPOT));
		
		//lcl_primitiviesMenu.addSeparator();
		
		//lcl_primitiviesMenu.add(buildAMenuItem(ADD_AREA_CLOD_MESH));
		
		mcl_menu.add(lcl_primitiviesMenu);
	}

	private	void	handleImportAction(String str_importExtension) {
		IImportFile		lcl_import = ModelUtils.getImporter(str_importExtension);
		lcl_import.doImportUI(mcl_node);
	}
	
	public void actionPerformed(ActionEvent cl_e) {
		if(cl_e.getActionCommand().equals(IMPORT_X3D)) {
			handleImportAction("x3d");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_MS3D)) {
			handleImportAction("ms3d");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_ASE)) {
			handleImportAction("ase");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_MD5)) {
			handleImportAction("md5");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_MD2)) {
			handleImportAction("md2");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_COLLADA_DAE)) {
			handleImportAction("dae");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_JME)) {
			handleImportAction("jme");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_OBJ)) {
			handleImportAction("obj");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_OGRE_XML)) {
			handleImportAction("xml");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_3DS)) {
			handleImportAction("3ds");
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_CHILD)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.IMPORT_CHILD_DIALOG);
			lcl_dlg.add(new ImportDialogPanel(mcl_node, lcl_dlg, true));
			lcl_dlg.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(IMPORT_FOLDER)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.IMPORT_CHILD_DIALOG);
			lcl_dlg.add(new ImportDialogPanel(mcl_node, lcl_dlg, false));
			lcl_dlg.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(NEW_TERRAIN)) {
			TerrainCreator		lcl_terrainCreator = new TerrainCreator(mcl_node);
			lcl_terrainCreator.setModal(true);
			lcl_terrainCreator.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(REORGANISE_CHILDREN)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.REORGANISE_CHILDREN);
			lcl_dlg.add(new ReorganiseChildrenPanel(mcl_node, lcl_dlg));
			lcl_dlg.pack();
			lcl_dlg.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(ADD_LENS_FLARE)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.CREATE_LENS_FLARE);
			lcl_dlg.add(new CreateLensFlarePanel(mcl_node, lcl_dlg));
			lcl_dlg.pack();
			lcl_dlg.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(ADD_FULL_SCREEN_QUAD)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					// TODO : Dialog this
					DisplaySystem		lcl_display = DisplaySystem.getDisplaySystem();
					Quad		lcl_quad = new Quad("fullScreen" + mcl_node.getQuantity(), lcl_display.getWidth(), lcl_display.getHeight());
					lcl_quad.getLocalRotation().set(0, 0, 0, 1);
					lcl_quad.getLocalTranslation().set(lcl_display.getWidth() / 2, lcl_display.getHeight() / 2, 0);
					lcl_quad.setLocalScale(1);
					lcl_quad.setRenderQueueMode(Renderer.QUEUE_ORTHO);
					lcl_quad.setCullHint(CullHint.Never);
					
					lcl_quad.updateRenderState();
					lcl_quad.updateGeometricState(0, true);
					
					mcl_node.attachChild(lcl_quad);
					return null;
				}
			});
		}
		
		final	CreateNewSpatial		lcl_creator = mcla_createObjectsCommands.get(cl_e.getActionCommand());
		if(lcl_creator == null) { return; }
		
		GameTaskQueueManager.getManager().update(new Callable<Object>() {
			public Object call() throws Exception {
				Spatial		lcl_new = lcl_creator.createSpatial(mcl_node);
				lcl_new.setModelBound(new BoundingSphere());
				lcl_new.updateModelBound();
				SceneWorkerGlobals.inst().pasteSpatial(mcl_node, lcl_new);
				mcl_node.updateRenderState();
				mcl_node.updateGeometricState(0, true);
				return null;
			}
		});
		
	}
	
	public	interface	CreateNewSpatial {
		Spatial	createSpatial(Node cl_parentNode);
	}
}
